package com.tengits.mqttmonitor;

import android.app.Application;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.content.Context;
import android.os.Build;
import android.os.Environment;
import android.text.TextUtils;

import com.facebook.react.PackageList;
import com.facebook.react.ReactApplication;
import com.facebook.react.ReactInstanceManager;
import com.facebook.react.ReactNativeHost;
import com.facebook.react.ReactPackage;
import com.facebook.soloader.SoLoader;
import com.microsoft.codepush.react.CodePush;
import com.tencent.bugly.Bugly;
import com.tencent.bugly.crashreport.CrashReport;
import com.tencent.mars.xlog.Log;
import com.tencent.mars.xlog.Xlog;
import com.tengits.mqttmonitor.rnlibs.alarm.AlarmLibraryPackage;
import com.tengits.mqttmonitor.rnlibs.logs.XLogLibraryPackage;
import com.tengits.mqttmonitor.rnlibs.mqttbroker.MQTTServerLibraryPackage;
import com.tengits.mqttmonitor.rnlibs.mqttclient.MQTTClientLibraryPackage;
import com.tengits.mqttmonitor.rnlibs.rs.SerialPortApiPackage;
import com.tengits.mqttmonitor.rnlibs.update.UpgradeLibraryPackage;
import com.tengits.mqttmonitor.rnlibs.utils.UtilLibraryPackage;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.List;

public class MQTTApplication extends Application implements ReactApplication {

  public static final String CHANNEL_ID = "mqttBrokerChannel";
  private static Context mContext;

  private final ReactNativeHost mReactNativeHost =
      new ReactNativeHost(this) {
        @Override
        public boolean getUseDeveloperSupport() {
          return BuildConfig.DEBUG;
        }

        @Override
        protected List<ReactPackage> getPackages() {
          @SuppressWarnings("UnnecessaryLocalVariable")
          List<ReactPackage> packages = new PackageList(this).getPackages();
          // Packages that cannot be autolinked yet can be added manually here, for example:
          packages.add(new UtilLibraryPackage());
          packages.add(new MQTTClientLibraryPackage());
          packages.add(new MQTTServerLibraryPackage());
          packages.add(new SerialPortApiPackage());
          packages.add(new XLogLibraryPackage());
          packages.add(new AlarmLibraryPackage());
          packages.add(new UpgradeLibraryPackage());
          return packages;
        }

        @Override
        protected String getJSMainModuleName() {
          return "index";
        }
        @Override
        protected String getJSBundleFile() {
            return CodePush.getJSBundleFile();
        }
      };

  @Override
  public ReactNativeHost getReactNativeHost() {
    return mReactNativeHost;
  }

  @Override
  public void onCreate() {
    super.onCreate();
    mContext = this;
    SoLoader.init(this, /* native exopackage */ false);
    initializeFlipper(this, getReactNativeHost().getReactInstanceManager());
      initXLog();
    Context context = getApplicationContext();
    // 获取当前包名
    String packageName = context.getPackageName();
    // 获取当前进程名
    String processName = getProcessName(android.os.Process.myPid());
    // 设置是否为上报进程
    CrashReport.UserStrategy strategy = new CrashReport.UserStrategy(context);
    strategy.setUploadProcess(processName == null || processName.equals(packageName));
    Bugly.init(getApplicationContext(), "723762e14d", BuildConfig.DEBUG, strategy);
    createNotificationChannel();
  }

  /**
   * Loads Flipper in React Native templates. Call this in the onCreate method with something like
   * initializeFlipper(this, getReactNativeHost().getReactInstanceManager());
   *
   * @param context
   * @param reactInstanceManager
   */
  private static void initializeFlipper(
      Context context, ReactInstanceManager reactInstanceManager) {
    if (BuildConfig.DEBUG) {
      try {
        /*
         We use reflection here to pick up the class that initializes Flipper,
        since Flipper library is not available in release mode
        */
        Class<?> aClass = Class.forName("com.mqttmonitor.ReactNativeFlipper");
        aClass
            .getMethod("initializeFlipper", Context.class, ReactInstanceManager.class)
            .invoke(null, context, reactInstanceManager);
      } catch (ClassNotFoundException e) {
        e.printStackTrace();
      } catch (NoSuchMethodException e) {
        e.printStackTrace();
      } catch (IllegalAccessException e) {
        e.printStackTrace();
      } catch (InvocationTargetException e) {
        e.printStackTrace();
      }
    }
  }

  /**
    * 获取进程号对应的进程名
    *
    * @param pid 进程号
    * @return 进程名
    */
  public static String getProcessName(int pid) {
      BufferedReader reader = null;
      try {
          reader = new BufferedReader(new FileReader("/proc/" + pid + "/cmdline"));
          String processName = reader.readLine();
          if (!TextUtils.isEmpty(processName)) {
              processName = processName.trim();
          }
          return processName;
      } catch (Throwable throwable) {
          throwable.printStackTrace();
      } finally {
          try {
              if (reader != null) {
                  reader.close();
              }
          } catch (IOException exception) {
              exception.printStackTrace();
          }
      }
      return null;
  }

  private void createNotificationChannel() {
      if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
          NotificationChannel serviceChannel = new NotificationChannel(
                  CHANNEL_ID,
                  "MQTTNotificationBroker",
                  NotificationManager.IMPORTANCE_DEFAULT
          );

          NotificationManager manager = getSystemService(NotificationManager.class);
          manager.createNotificationChannel(serviceChannel);
      }
  }

  private void initXLog() {
      final String SDCARD = Environment.getExternalStorageDirectory().getAbsolutePath();
      final String logPath = SDCARD + "/tengits_mqtt/log";
      final String cachePath = this.getFilesDir() + "/xlog";
      Xlog xlog = new Xlog();
      Log.setLogImp(xlog);

      if (BuildConfig.DEBUG) {
          Log.setConsoleLogOpen(true);
          Log.appenderOpen(Xlog.LEVEL_DEBUG, Xlog.AppednerModeAsync, cachePath, logPath, "monitor", 0);
      } else {
          Log.setConsoleLogOpen(false);
          Log.appenderOpen(Xlog.LEVEL_INFO, Xlog.AppednerModeAsync, cachePath, logPath, "monitor", 0);
      }
  }

  public static Context getContext() {
    return mContext;
  }

    static {
        System.loadLibrary("c++_shared");
        System.loadLibrary("marsxlog");
    }
}
